package com.longteng.diamond.util;
import com.alibaba.fastjson.JSON;
import com.jayway.jsonpath.JsonPath;
import com.longteng.diamond.constant.BuildTestStatus;
import com.longteng.diamond.domain.BuildTestCase;
import com.longteng.diamond.domain.RunTestContext;
import com.longteng.diamond.service.impl.XPathMatchImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.test.util.AssertionErrors;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;

/**
 * Created by taki
 * DATE : 2018/9/3 0003
 * TIME : 22:58
 * PROJECT : java-lesson
 * PACKAGE : com.longteng.lesson
 *
 * @author <a href="mailto:165157905@qq.com">taki</a>
 */
@Component
@Slf4j
public class AssertResult {
    @Autowired
    XPathMatchImpl xPathMatch;
    @Autowired
    ReplaceUtil replaceUtil;
    /**
     * 断言
     *
     * @param runTestContext
     * @return
     */
    public void assertResult(RunTestContext runTestContext) {
        BuildTestCase buildTestCase = runTestContext.getBuildTestCase();
        String actualResult = buildTestCase.getActualResult();
        ReportLogFileUtil logFileUtil = runTestContext.getReportLogFileUtil();
        logFileUtil.write("测试用例[" + buildTestCase.getTestCaseName() + "]执行断言");
        if(!StringUtils.isBlank(actualResult)){
            actualResult=replaceUtil.remove(actualResult);
        }else {
            buildTestCase.setStatus(BuildTestStatus.fail);
            runTestContext.setInterfaceFailSize(1);
            logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]预期结果为null无法校验");
            logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]断言校验未通过");
            return;
        }
        String expectResult =replaceUtil.remove(buildTestCase.getExpectResult());
        buildTestCase.setStatus(BuildTestStatus.pass);
        List<String> expressionList=null;
        switch (buildTestCase.getMatchType()) {
            case 1:
                if (!expectResult.equalsIgnoreCase(actualResult)) {
                    buildTestCase.setStatus(BuildTestStatus.fail);
                    buildTestCase.setErrorMsg("全文比对不通过");
                }
                break;
            case 2:
                if (!actualResult.contains(expectResult)) {
                    buildTestCase.setStatus(BuildTestStatus.fail);
                    buildTestCase.setErrorMsg("实际结果包含预期结果");
                }
                break;
            case 3:
                if (actualResult.contains(expectResult)) {
                    buildTestCase.setStatus(BuildTestStatus.fail);
                    buildTestCase.setErrorMsg("实际结果未包含预期结果");
                }
                break;
            case 4:
                if(!StringUtils.isBlank(buildTestCase.getMatchExpression())) {
                    try {
                        expressionList = JSON.parseObject(buildTestCase.getMatchExpression(), List.class);
                    }catch (Exception e){
                        log.error("反序列化jsonPath表达式异常",e);
                        logFileUtil.writeRedSpan("反序列化jsonPath表达式异常,请联系管理员");
                        buildTestCase.setStatus(BuildTestStatus.fail);
                        buildTestCase.setErrorMsg("反序列化jsonPath表达式异常,请联系管理员");
                        break;
                    }
                }
                for (String expression : expressionList) {
                    try {
                       Object expect = JsonPath.read(expectResult, expression);
                       Object actual =JsonPath.read(actualResult, expression);
                       try {
                           AssertionErrors.assertEquals("", expect, actual);
                       }catch (AssertionError error){
                           buildTestCase.setStatus(BuildTestStatus.fail);
                           buildTestCase.setErrorMsg(error.getMessage());
                           logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]断言校验未通过");
                           logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]"+error.getMessage());
                           break;
                       }
                    } catch (Exception e) {
                        buildTestCase.setStatus(BuildTestStatus.fail);
                        buildTestCase.setErrorMsg(e.getMessage());
                        logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]断言校验未通过");
                        logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]"+e.getMessage());
                        break;
                    }
                }
                break;
            case 5:
                /**获取入参数据并且转换成document**/
                Document expectDocument;
                Document actualDocument;
                try {
                    expectResult=expectResult.replace("&lt;","<").replace("&gt;",">");
                    InputStream is = new ByteArrayInputStream(expectResult.getBytes());
                    expectDocument = xPathMatch.getDocumentObj(is);
                }catch (Exception e){
                    log.error("获取预期结果document异常",e);
                    buildTestCase.setStatus(BuildTestStatus.fail);
                    buildTestCase.setErrorMsg("获取预期结果document异常:"+e);
                    logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]获取预期结果document异常");
                    logFileUtil.writeRedSpan(e.getMessage());
                    break;
                }
                try {
                    InputStream is = new ByteArrayInputStream(actualResult.getBytes());
                    actualDocument = xPathMatch.getDocumentObj(is);
                }catch (Exception e){
                    log.error("获取实际结果document异常",e);
                    buildTestCase.setStatus(BuildTestStatus.fail);
                    buildTestCase.setErrorMsg("获取实际结果document异常:"+e);
                    logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]获取实际结果document异常");
                    logFileUtil.writeRedSpan(e.getMessage());
                    break;
                }
                /**定义一个xPath解析器**/
                XPath xPath= XPathFactory.newInstance().newXPath();
                if(!StringUtils.isBlank(buildTestCase.getMatchExpression())) {
                    try{
                        expressionList = JSON.parseObject(buildTestCase.getMatchExpression(), List.class);
                    }catch (Exception e){
                        log.error("反序列化XPath表达式异常",e);
                        buildTestCase.setStatus(BuildTestStatus.fail);
                        buildTestCase.setErrorMsg("反序列化XPath表达式异常,请联系管理员");
                        logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]反序列化XPath表达式异常,请联系管理员");
                        logFileUtil.writeRedSpan(e.getMessage());
                        break;
                    }
                }
                for (String expression : expressionList) {
                    try {
                        Node expectNode=(Node) xPath.evaluate(expression,expectDocument,XPathConstants.NODE);
                        Node actualNode=(Node) xPath.evaluate(expression,actualDocument,XPathConstants.NODE);
                        if(null==expectNode){
                            buildTestCase.setStatus(BuildTestStatus.fail);
                            buildTestCase.setErrorMsg("预期结果表达式["+expression+"]获取的结果为空");
                            logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]预期结果表达式["+expression+"]获取的结果为空");
                            break;
                        }
                        if(null==actualNode){
                            buildTestCase.setStatus(BuildTestStatus.fail);
                            buildTestCase.setErrorMsg("实际结果表达式["+expression+"]获取的结果为空");
                            logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]实际结果表达式["+expression+"]获取的结果为空");
                            break;
                        }
                        Object expectValue=expectNode.getNodeValue();
                        Object actualValue=actualNode.getNodeValue();
                        try {
                            AssertionErrors.assertEquals("", expectValue, actualValue);
                        }catch (AssertionError error){
                            buildTestCase.setStatus(BuildTestStatus.fail);
                            buildTestCase.setErrorMsg(error.getMessage());
                            logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]断言校验未通过");
                            logFileUtil.writeRedSpan(error.getMessage());
                            break;
                        }
                    } catch (Exception e) {
                        buildTestCase.setStatus(BuildTestStatus.fail);
                        buildTestCase.setErrorMsg(e.getMessage());
                        logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]断言校验未通过");
                        logFileUtil.writeRedSpan(e.getMessage());
                    }
                }
                //xpath
                break;
            case 6:
                //reg
                break;
            default:
                break;
        }
        Integer status = buildTestCase.getStatus();
        if (status.intValue() == BuildTestStatus.fail) {
            buildTestCase.setStatus(BuildTestStatus.fail);
            runTestContext.setInterfaceFailSize(1);
            logFileUtil.writeRedSpan("测试用例[" + buildTestCase.getTestCaseName() + "]断言校验未通过");
//            logFileUtil.writeRedSpan("预期结果:");
//            logFileUtil.writeRedSpan(expectResult);
//            logFileUtil.writeRedSpan("实际结果:");
//            logFileUtil.writeRedSpan(actualResult);
        } else {
            runTestContext.setInterfacePassSize(1);
            logFileUtil.writeGreenSpan("测试用例[" + buildTestCase.getTestCaseName() + "]断言校验通过");
        }
    }
}
